<template>
  <div class="terminal-container"></div>
</template>

<script>
import 'xterm/css/xterm.css'

import {Terminal} from 'xterm'
import {FitAddon} from 'xterm-addon-fit'

// 防抖
import {debounce} from 'lodash'

import Socket from './socket'

export default {
  name: "xTerminal",

  props: {

    /**
     * 连接信息
     */
    connInfo: {
      type: Object,
      default: () => {
        return {
          host: null,
          port: null,
          username: null,
          password: null
        }
      }
    },

    isActive: {
      type: Function,
      default: function () {
        return true
      }
    }

  },

  data() {
    return {

      id: `xterm-${new Date().getTime()}`,

      /**
       * xterm.js中Terminal对象
       */
      term: null,

      /**
       *
       */
      fitAddon: null,

      /**
       * xterm的配置
       */
      config: {
        // 启用时，光标将设置为下一行的开头
        convertEol: true,

        // 终端的回滚量
        scrollback: 50,

        // 是否禁止输入
        disableStdin: false,

        // 光标样式： 'block' | 'underline' | 'bar'
        cursorStyle: 'bar',

        // 光标的宽度，只有当设置cursorStyle='bar'时才会生效
        cursorWidth: 4,

        // 光标闪烁
        cursorBlink: true,

        // 字体大小
        fontSize: 18,

        // 字体
        // fontFamily: 'monospace’,
        // 字符间距
        letterSpacing: 2,
        fontFamily:'monospace',
        // 行高
        lineHeight: 1,

        // 主题，具体属性可参考 {@link node_modules/xterm/typings/xterm.d.ts}
        theme: {
          background: '#0C0C0C',
          foreground: '#CCCCCC',
          cursor: '#ffffff',
          selectionBackground:'#868686',
        }
      },

      socket: null,

      uninstall: false
    }
  },

  mounted() {
    this.config['rows'] = this.getRows()
    this.config['cols'] = this.getCols()

    // 创建Terminal
    this.term = new Terminal(this.config)
    this.term.open(this.$el)

    this.consoleInit()

    // 让Terminal的宽度自适应
    this.fitAddon = new FitAddon()
    this.term.loadAddon(this.fitAddon)
    this.fitAddon.fit()

    // 加载socket
    this.loadSocket()

    /**
     * 监听用户按键事件
     */
    this.term.onData(key => {
      if (!this.socket || !this.socket.is()) {
        return
      }
      console.log("用户按键key:"+key)
      this.socket.send({
        type: 'command',
        message: key
      })
    })

    // 监听页面大小的变化
    this.litenerResize()
  },

  methods: {
    /**
     * 根据容器宽度计算cols
     * @returns {number}
     */
    getCols() {
      const cols = document.querySelector(".terminal-container").offsetWidth / 14
      return parseInt(cols)
    },

    /**
     * 根据容器高度计算rows
     * @returns {number}
     */
    getRows() {
      const rows = document.querySelector(".terminal-container").offsetHeight / 16 - 50
      if (rows <= 5) {
        return 30;
      } else {
        return parseInt(rows)
      }
    },

    /**
     * 在终端内打印初始化提示信息
     */
    consoleInit() {
      this.term.writeln('Welcome to the Online Programming Learning Platform!')
      this.term.writeln('     Copyright ©️ 2023-present Learning Platform')
    },

    /**
     * 重置终端
     */
    reset() {
      this.term.reset()
      this.consoleInit()
    },

    /**
     * 关闭
     */
    close() {
      this.socket.close()
    },

    /**
     * 重置大小
     */
    resize() {
      try {
        this.fitAddon.fit()

        this.term.onResize(() => {
          // TODO 列和行数重新定义
        })
      } catch (e) {
        console.log(e)
      }
    },

    /**
     * 监听页面发生变化
     */
    litenerResize() {
      window.addEventListener('resize', debounce(() => {
        if (this.uninstall || !this.isActive(this.connInfo._key)) {
          return
        }

        this.resize()
      }, 100))
    },

    /**
     * 加载WebSocket
     */
    loadSocket() {
      // 如果host为空，则不需要连接
      if (!this.connInfo.host) {
        return
      }

      const _this = this

      this.socket = new Socket('wss://hubujyjs.cn:8080/ssh', {
      // this.socket = new Socket('ws://localhost:8000/ssh', {
        onopen() {
          _this.reset()

          _this.term.writeln(`连接到 ${_this.connInfo.host}:${_this.connInfo.port} ...`)

          this.send({
            type: 'connect',
            message: _this.connInfo
          })

        },

        onmessage(data) {
          console.log("服务器返回数据"+data)
          if (data.endsWith("连接失败")) {
            this.close()
            return
          }

          if (data.length === 3) {
            _this.term.write(data.trim())
          } else {
            _this.term.write(data)
          }
        },

        afterClose() {

        }

      }).init()
    }

  },

  /**
   * 组件销毁之前标记一下unisntall为true，表示已被卸载
   */
  beforeDestroy() {
    this.uninstall = true
  }
}
</script>

<style>

.terminal-container {
  width: 100%;
  height: 100%;
}

</style>
